package nl.weeaboo.sh.editor.area;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;

import nl.weeaboo.sh.model.AreaModel;
import nl.weeaboo.sh.model.RoomModel;
import timon.common.components.GuiUtil;
import timon.common.components.Sash;

@SuppressWarnings("serial")
public class RoomToolPanel extends JPanel {

	private Palette palette;
	private AreaModel area;
	private RoomModel room;
	
	public RoomToolPanel(Palette palette) {
		this.palette = palette;
		
		setLayout(new BorderLayout(5, 5));
		add(createMainPanel(), BorderLayout.WEST);
		
		GuiUtil.recursiveSetEnabled(this, false);		
	}
	
	//Functions
	private JPanel createMainPanel() {
		final JSpinner splitHSpinner = new JSpinner(new SpinnerNumberModel(1, 1, 999, 1));
		final JSpinner splitVSpinner = new JSpinner(new SpinnerNumberModel(1, 1, 999, 1));
		
		JButton splitHButton = new JButton("Split --");
		splitHButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				splitH((Integer)splitHSpinner.getValue());
			}
		});

		JButton splitVButton = new JButton("Split |");
		splitVButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				splitV((Integer)splitVSpinner.getValue());
			}
		});
		
		JButton mergeButton = new JButton("Merge");
		mergeButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				RoomBrowser roomBrowser = new RoomBrowser();
				roomBrowser.setArea(area);
				JScrollPane scrollPane = new JScrollPane(roomBrowser);
				scrollPane.setPreferredSize(new Dimension(200, 300));
				
				int result = JOptionPane.showConfirmDialog(null, scrollPane,
						"Select room to merge with...",
						JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
				
				if (result == JOptionPane.OK_OPTION) {
					merge(room, roomBrowser.getSelectedValue());
				}
			}
		});
		
		final JSpinner stretchSpinner = new JSpinner(new SpinnerNumberModel(1, 1, 999, 1));
		
		JButton stretchLeftButton = new JButton("Stretch L");
		stretchLeftButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				stretch(-(Integer)stretchSpinner.getValue(), 0);
			}
		});
		
		JButton stretchRightButton = new JButton("Stretch R");
		stretchRightButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				stretch((Integer)stretchSpinner.getValue(), 0);
			}
		});
		
		JButton stretchUpButton = new JButton("Stretch U");
		stretchUpButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				stretch(0, -(Integer)stretchSpinner.getValue());
			}
		});
		
		JButton stretchDownButton = new JButton("Stretch D");
		stretchDownButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				stretch(0, (Integer)stretchSpinner.getValue());
			}
		});
		
		JPanel leftPanel = new JPanel(new GridLayout(-1, 2, 5, 5));
		leftPanel.add(splitHSpinner); leftPanel.add(splitHButton);
		leftPanel.add(splitVSpinner); leftPanel.add(splitVButton);		
		leftPanel.add(mergeButton);
		
		JPanel rightPanel = new JPanel(new GridLayout(-1, 1, 5, 5));
		rightPanel.add(stretchSpinner);
		rightPanel.add(stretchLeftButton);
		rightPanel.add(stretchRightButton);
		rightPanel.add(stretchUpButton);
		rightPanel.add(stretchDownButton);
		
		JPanel hPanel = new JPanel();
		hPanel.setLayout(new BoxLayout(hPanel, BoxLayout.X_AXIS));
		hPanel.add(leftPanel); leftPanel.setAlignmentY(1f);
		hPanel.add(Box.createHorizontalStrut(10));
		hPanel.add(new Sash(Sash.VERTICAL));
		hPanel.add(Box.createHorizontalStrut(10));
		hPanel.add(rightPanel);
		
		JPanel panel = new JPanel(new BorderLayout(5, 5));
		panel.add(hPanel, BorderLayout.NORTH);
		return panel;
	}
	
	protected void splitH(int y) {
		if (y == 0 || y >= room.getHeight()) return;
		
		RoomModel r2 = room.clone();
		r2.setId(area.generateRoomId());
		
		Point p = new Point();
		for (Integer i : r2.getLayerIndices()) {
			for (p.y = 0; p.y < r2.getHeight(); p.y++) {
				for (p.x = 0; p.x < r2.getWidth(); p.x++) {
					r2.setTile(i, p.x, p.y - y, r2.getTile(i, p));
					r2.setTile(i, p.x, p.y, null);
				}
			}
		}
		
		room.setSize(room.getWidth(), y);
		r2.setOffset(r2.getX(), r2.getY() + y);
		r2.setSize(r2.getWidth(), r2.getHeight() - y);

		area.addRoom(r2);
		palette.onRoomsChanged();
	}
	protected void splitV(int x) {
		if (x == 0 || x >= room.getWidth()) return;
		
		RoomModel r2 = room.clone();
		r2.setId(area.generateRoomId());
		
		Point p = new Point();
		for (Integer i : r2.getLayerIndices()) {
			for (p.y = 0; p.y < r2.getHeight(); p.y++) {
				for (p.x = 0; p.x < r2.getWidth(); p.x++) {
					r2.setTile(i, p.x - x, p.y, r2.getTile(i, p));
					r2.setTile(i, p.x, p.y, null);
				}
			}
		}
		
		room.setSize(x, room.getHeight());
		r2.setOffset(r2.getX() + x, r2.getY());
		r2.setSize(r2.getWidth() - x, r2.getHeight());
		
		area.addRoom(r2);
		palette.onRoomsChanged();
	}
	protected void merge(RoomModel r1, RoomModel r2) {
		Rectangle r1b = r1.getBounds();
		Rectangle r2b = r2.getBounds();
		Rectangle combined = new Rectangle(Math.min(r1b.x, r2b.x), Math.min(r1b.y, r2b.y), 0, 0);
		combined.width = Math.max(r1b.x+r1b.width, r2b.x+r2b.width) - combined.x;
		combined.height = Math.max(r1b.y+r1b.height, r2b.y+r2b.height) - combined.y;
		
		if (combined.width != r1b.width && combined.height != r1b.height) {
			JOptionPane.showMessageDialog(null, "Rooms don't align properly", "Error",
					JOptionPane.ERROR_MESSAGE);
			return;
		}
		
		RoomModel r = r1.clone();
		for (Integer i : r1.getLayerIndices()) {
			for (int y = 0; y < r1.getHeight(); y++) {
				for (int x = 0; x < r1.getWidth(); x++) {
					r.setTile(i, x, y, null);
				}
			}
		}
		
		r.setOffset(combined.x, combined.y);
		r.setSize(combined.width, combined.height);
		
		int tx, ty;		
		Point p = new Point();
		
		tx = r1.getX() - combined.x;
		ty = r1.getY() - combined.y;
		for (Integer i : r1.getLayerIndices()) {
			for (p.y = 0; p.y < r1.getHeight(); p.y++) {
				for (p.x = 0; p.x < r1.getWidth(); p.x++) {
					r.setTile(i, p.x+tx, p.y+ty, r1.getTile(i, p));
				}
			}
		}
		
		tx = r2.getX() - combined.x;
		ty = r2.getY() - combined.y;
		for (Integer i : r2.getLayerIndices()) {
			for (p.y = 0; p.y < r2.getHeight(); p.y++) {
				for (p.x = 0; p.x < r2.getWidth(); p.x++) {
					r.setTile(i, p.x+tx, p.y+ty, r2.getTile(i, p));
				}
			}
		}
		
		area.removeRoom(r1);
		area.removeRoom(r2);
		
		r.setId(r1.getId());
		area.addRoom(r);
		palette.onRoomsChanged();
	}
	protected void stretch(int dx, int dy) {
		room.setSize(room.getWidth() + Math.abs(dx), room.getHeight() + Math.abs(dy));
		if (dx >= 0 && dy >= 0) {
			palette.onRoomsChanged();
			return;
		}
		
		if (dx > 0) dx = 0;
		if (dy > 0) dy = 0;
		
		room.setOffset(room.getX() + dx, room.getY() + dy);
		
		Point p = new Point();
		for (Integer i : room.getLayerIndices()) {
			for (p.y = room.getHeight()-1; p.y >= 0; p.y--) {
				for (p.x = room.getWidth()-1; p.x >= 0; p.x--) {
					room.setTile(i, p.x - dx, p.y - dy, room.getTile(i, p));
					room.setTile(i, p.x, p.y, null);
				}
			}
		}
		
		palette.onRoomsChanged();
	}
	
	//Getters
	
	//Setters
	public void setSelectedRoom(AreaModel a, RoomModel r) {
		area = a;
		if (room != r) {
			room = r;
			
			GuiUtil.recursiveSetEnabled(this, room != null);
		}
	}
}
